/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
  (C)2013 Semtech-Cycleo

Description:
    Host specific functions to address the LoRa concentrator registers through
    a SPI interface.
    Single-byte read/write and burst read/write.
    Does not handle pagination.
    Could be used with multiple SPI ports in parallel (explicit file descriptor)

License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Sylvain Miermont
*/


/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */

#include <stdint.h>        /* C99 types */
#include <stdio.h>        /* printf fprintf */
#include <stdlib.h>        /* malloc free */
#include <string.h>        /* memset */

#include "loragw_spi.h"
#include "gw-device.h"

#include "pthread.h"

#include "esp_log.h"




/* -------------------------------------------------------------------------- */
/* --- PRIVATE MACROS ------------------------------------------------------- */

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))




/* -------------------------------------------------------------------------- */
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */

#define READ_ACCESS     0x00
#define WRITE_ACCESS    0x80


/*!
 * SPI Handler struct
 */
spi_device_handle_t lora_spi = NULL;
static pthread_mutex_t mx_spi = PTHREAD_MUTEX_INITIALIZER; /* control access to the downstream measurements */

/* -------------------------------------------------------------------------- */
/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
void spi_init()
{
    esp_err_t ret;
    
    spi_bus_config_t buscfg={
        .miso_io_num=PIN_NUM_MISO,
        .mosi_io_num=PIN_NUM_MOSI,
        .sclk_io_num=PIN_NUM_CLK,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
        .max_transfer_sz=4096*2
    };
    spi_device_interface_config_t devcfg={
        .clock_speed_hz=SPI_MASTER_FREQ_8M,           //Clock out at 10 MHz
        .mode=0,                                //SPI mode 0
        .spics_io_num=PIN_NUM_CS,               //CS pin
        .queue_size=7,                          //We want to be able to queue 7 transactions at a time
        .pre_cb=NULL,  
        .address_bits = 8,
        // .flags=SPI_DEVICE_HALFDUPLEX,
    };
    //Initialize the SPI bus
    ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(HSPI_HOST, &devcfg, &lora_spi);
    ESP_ERROR_CHECK(ret);

    // spi_mutex = xSemaphoreCreateMutex();  
    // if(spi_mutex == NULL)
    // {
    //     printf("create spi_mutex failed \n");  
    // }
    // else 
    // {
    //     xSemaphoreGive(spi_mutex);
    // }
    
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

/* Burst (multiple-byte) write */
esp_err_t lgw_spi_wb(uint8_t address, uint8_t *data, uint16_t size) 
{
    spi_transaction_t k;
    esp_err_t ret;

    /* I/O transaction */
    memset(&k, 0, sizeof(k)); /* clear k */
    k.addr = address;
    k.tx_buffer = data;
    k.length = size*8;

    pthread_mutex_lock(&mx_spi);
    SPI_PRINTF("%s xSemaphoreTake take success\n",__func__);
    ret=spi_device_transmit(lora_spi, &k);  //Transmit!
    assert(ret==ESP_OK);                //Should have had no issues.  
    pthread_mutex_unlock(&mx_spi);

    SPI_PRINTF("SPI write\n");
    SPI_PRINTF("0x%.2x ",address);
    for(int i=0;i<k.length/8;i++)
    {
        SPI_PRINTF("0x%.2x ",data[i]);
    }
    SPI_PRINTF("\n");

    return ESP_OK;
}

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

/* Burst (multiple-byte) read */
esp_err_t lgw_spi_rb(uint8_t address, uint8_t *data, uint16_t size)
{
    spi_transaction_t k;
    esp_err_t ret;

    /* I/O transaction */
    memset(&k, 0, sizeof(k)); /* clear k */
    k.addr = address;
    k.length = size*8;
    k.rx_buffer = data;
    // k.rxlength = size*8;

    if(size > 256)
    {
        CON_PRINTF("SPI RB ERROR\n");
    }

    pthread_mutex_lock(&mx_spi);
    SPI_PRINTF("%s xSemaphoreTake take success\n",__func__);
    ret=spi_device_transmit(lora_spi, &k);  //Transmit!
    assert(ret==ESP_OK);                //Should have had no issues.  
    pthread_mutex_unlock(&mx_spi);

    SPI_PRINTF("SPI Read\n");
    SPI_PRINTF("address:0x%.2x\ndata: ",address);
    for(int i=0;i<k.rxlength/8;i++)
    {
        SPI_PRINTF("0x%.2x ",data[i]);
    }
    SPI_PRINTF("\n");

    return ESP_OK;
}

/* --- EOF ------------------------------------------------------------------ */
